﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient.ResourceManagement;
using Microsoft.ResourceManagement.Utilities;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
using Microsoft.ResourceManagement.Workflow.Activities;

namespace Ensynch.ILM2.Workflow.Activities
{
    public partial class OwnerRollupActivity : SequenceActivity
    {
        public String PrimaryOwner;
        public String PrimaryOwnerNew;

        public OwnerRollupActivity()
        {
            InitializeComponent();
        }

        #region Class properties

        public static DependencyProperty TheActivityNameProperty =
                    DependencyProperty.Register("TheActivityName", typeof(string), typeof(OwnerRollupActivity));

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("Properties")]
        public string TheActivityName
        {
            get
            {
                object test = this.GetValue(OwnerRollupActivity.TheActivityNameProperty);
                return test == null ? "" : test.ToString();
            }
            set
            {
                this.SetValue(OwnerRollupActivity.TheActivityNameProperty, value);
            }
        }

        public static DependencyProperty PrimaryOwnerGrammarProperty =
                    DependencyProperty.Register("PrimaryOwnerGrammar", typeof(string), typeof(OwnerRollupActivity));

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("Properties")]
        public string PrimaryOwnerGrammar
        {
            get
            {
                object test = this.GetValue(OwnerRollupActivity.PrimaryOwnerGrammarProperty);
                return test == null ? "" : test.ToString();
            }
            set
            {
                this.SetValue(OwnerRollupActivity.PrimaryOwnerGrammarProperty, value);
            }
        }

        public static DependencyProperty BuilderFilterProperty = DependencyProperty.Register("BuilderFilter", typeof(System.String), typeof(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity));

        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(true)]
        [CategoryAttribute("Misc")]
        public String BuilderFilter
        {
            get
            {
                return ((string)(base.GetValue(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity.BuilderFilterProperty)));
            }
            set
            {
                base.SetValue(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity.BuilderFilterProperty, value);
            }
        }

        public static DependencyProperty CustomFilterProperty = DependencyProperty.Register("CustomFilter", typeof(System.String), typeof(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity));

        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(true)]
        [CategoryAttribute("Misc")]
        public String CustomFilter
        {
            get
            {
                return ((string)(base.GetValue(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity.CustomFilterProperty)));
            }
            set
            {
                base.SetValue(Ensynch.ILM2.Workflow.Activities.OwnerRollupActivity.CustomFilterProperty, value);
            }
        }

        public string TheXPathFilter
        {
            get
            {
                if (!string.IsNullOrEmpty(CustomFilter))
                {
                    return CustomFilter;
                }
                else
                {
                    return BuilderFilter;
                }
            }
            set { } // Property cannot be read-only.
        }

        private List<string> candidates;

        public List<string> Candidates
        {
            get
            {
                if (candidates == null)
                {
                    candidates = enumerateCandidates();
                }
                return candidates;
            }
        }

        #endregion

        #region Private methods

        private void _computePrimaryOwner(object sender, EventArgs e)
        {
            // Begin with some default settings.
            PrimaryOwnerNew = PrimaryOwner;

            bool success = false;

            // Check if primary owner already satisfies the requirements.
            success = interrogatePrimaryOwner();

            if (!success)
            {
                // Check if primary owner's managers satisfy the requirements.
                success = interrogatePrimaryOwnerManagers();
            }

            if (!success)
            {
                // Your failsafe condition here
            }
        }

        private bool interrogatePrimaryOwner()
        {
            bool success = false;

            success = interrogateObject(PrimaryOwner);

            return success;
        }

        private bool interrogatePrimaryOwnerManagers()
        {
            List<string> managers = new List<string>();
            bool success = interrogateManagers(PrimaryOwner, managers);
            return success;
        }

        private bool interrogateManagers(string objectID, List<string> managers)
        {
            bool success = false;

            string xpath =
                "/Person[ObjectID = '" + objectID + "']/Manager";
            List<string> objectIDs = enumerateObjects(xpath);

            // The objectIDs list shouldn't contain more than one object, but just in case.
            foreach (string obj in objectIDs)
            {
                string manager = obj.ToLower();

                /// Keep track of the managers we've interrogated, in case we encounter
                /// a circular reference.
                if (!managers.Contains(manager))
                {
                    managers.Add(manager);

                    // Interrogate the manager, and break out of the loop upon success.
                    success = interrogateObject(manager);
                    if (success)
                    {
                        break;
                    }

                    // Keep going up the chain until we find a match.
                    success = interrogateManagers(manager, managers);
                    if (success)
                    {
                        break;
                    }
                }
            }

            return success;
        }

        private bool interrogateObject(string objectID)
        {
            bool success = false;

            if (Candidates.Contains(objectID.ToLower()))
            {
                PrimaryOwnerNew = objectID;
                success = true;
            }

            return success;
        }

        private List<string> enumerateCandidates()
        {
            return enumerateObjects(TheXPathFilter);
        }

        private List<string> enumerateObjects(string xpath)
        {
            List<string> objectIDs = new List<string>();

            WSEnumerationClient enumerationClient = new WSEnumerationClient();

            List<string> selectionAttributes = null;
            List<string> sortingAttributes = null;

            selectionAttributes = new List<string> {
                "ObjectID"
            };

            enumerationClient.Enumerate(xpath, selectionAttributes, sortingAttributes);
            while (enumerationClient.IsContextValid)
            {
                foreach (ResourceManagementObject person in enumerationClient.Pull())
                {
                    objectIDs.Add(
                        person["ObjectID"].AttributeSingleValue.ToString()
                        .ToLower().Replace("urn:uuid:", ""));
                }
            }

            return objectIDs;
        }

        #endregion


    }
}
